home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / uip / msg / msg3.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-11  |  17.0 KB  |  879 lines

  1. /*
  2.  *            M S G 3 . C
  3.  *
  4.  * This is the third part of the MSG program.
  5.  *
  6.  * Functions -
  7.  *    xeq        run a sub-process
  8.  *    help        supply help
  9.  *    gitr        get message range
  10.  *    gitrtype    get message range type details
  11.  *    gitrnum        get message range -- numeric
  12.  *    unset        clear all "Process it" flags
  13.  *    cntproc        count number of messages to be processed
  14.  *    setrange    mark group of messages to process
  15.  *    settype        mark all messages according to type command
  16.  *    getnum        input a decimal number
  17.  *    doiter        apply a function to all marked messages
  18.  *    resend        resend message to addresses
  19.  *    sortbox        sort msg box
  20.  *    qcomp        qsort comparison routine
  21.  *
  22.  *        R E V I S I O N   H I S T O R Y
  23.  *
  24.  *    06/09/82  MJM    Split the enormous MSG program into pieces.
  25.  *
  26.  *    03/16/83  MJM    Decoupled "inverse" from "all".
  27.  */
  28. #include "util.h"
  29. #include "mmdf.h"
  30. #include <pwd.h>
  31. #include <signal.h>
  32. #include <sys/stat.h>
  33. #include <sgtty.h>
  34. #ifdef V4_2BSD
  35. #include <sys/wait.h>
  36. #endif V4_2BSD
  37. #include "./msg.h"
  38.  
  39. /*
  40.  *            X E Q
  41.  *
  42.  *  Execute some program, such as SEND or the Shell.
  43.  */
  44. sigtype (*old2)();
  45. sigtype (*old3)();
  46. sigtype (*old13)();
  47. sigtype (*old18)();
  48.  
  49. xeq( exflag)
  50. char exflag;
  51. {
  52.     int process;
  53. #ifdef V4_2BSD
  54.     union wait pstatus;
  55. #else V4_2BSD
  56.     int    pstatus;
  57. #endif V4_2BSD
  58.     char *routine;
  59.  
  60.     tt_norm();
  61.     old2 = signal( SIGINT, SIG_IGN);
  62.     old13 = signal( SIGPIPE, SIG_IGN);
  63. #ifdef SIGTSTP
  64.     old18 =    signal( SIGTSTP, SIG_DFL);
  65. #endif SIGTSTP
  66.  
  67.     process = fork();
  68.     if( !process)  {
  69.         int    fd;
  70.  
  71.         signal( SIGINT, orig);
  72.         signal( SIGQUIT, old3);
  73.         signal( SIGPIPE, old13);
  74.  
  75. #ifndef V4_2BSD
  76.         for (fd = _NFILE-1; fd > 2; fd--)
  77. #else
  78.         for (fd = getdtablesize()-1; fd > 2; fd--)
  79. #endif
  80.             close (fd);
  81.  
  82.         switch( exflag)  {
  83.  
  84.         case 'a':           /* answer send fork */
  85.             execlp( routine = sndname, sndname, sndto, "-c", sndcc,
  86.                 "-s", sndsubj, (char *)0);
  87.             break;
  88.  
  89.         case 'A':
  90.             /* Invoke SEND after 2-window edit */
  91.             execlp( routine = sndname, sndname, sndto, "-c", sndcc,
  92.                 "-s", sndsubj, "-f", draft_work, "-n", (char *)0);
  93.             break;
  94.  
  95.         case 'd': 
  96.             execlp( routine = "date", "date", (char *)0);
  97.             break;
  98.  
  99.         case 'e':        /* 2-window edit */
  100.             execlp( routine = twowinfil, ueditor,
  101.                 draft_original, draft_work, (char *)0 );
  102.             break;
  103.  
  104.         case 'f':           /* forward send fork */
  105.             execlp( routine = sndname, sndname, "-f", outfile,
  106.               "-c", (isnull( sndsubj[0]) ? (char *)0 : "-s"),
  107.               sndsubj, (char *)0);
  108.             break;
  109.  
  110.         case 'j':           /* One command shell fork */
  111.             if( verbose)  {
  112.                 printf( "jump into lower shell running: ");
  113.                 fflush(stdout);
  114.             }
  115.             execlp( routine = ushell, ushell, "-t", (char *)0);
  116.             break;
  117.  
  118.         case 's':        /* shell fork */
  119.             execlp( routine = ushell, ushell, (char *)0);
  120.             break;
  121.  
  122.         case '!':        /* shell fork */
  123.             execlp( routine = ushell, ushell, "-c", key, (char *)0 );
  124.             break;
  125.  
  126.         case 'S':           /* send fork */
  127.             execlp( routine = sndname, sndname, (char *)0);
  128.             break;
  129.         }
  130.         fprintf (stderr, "Can't execute %s\r\n", routine);
  131.         closeup(-1);
  132.     }  else  {
  133.         while (wait( &pstatus ) != -1) ;
  134.  
  135.         signal( SIGINT, old2);
  136.         signal( SIGQUIT, SIG_IGN);
  137.         signal( SIGPIPE, old13);
  138. #ifdef SIGTSTP
  139.         signal( SIGTSTP, old18);
  140. #endif SIGTSTP
  141.         tt_init();        /* in case he changed the ttymodes */
  142.     }
  143.     tt_raw();
  144. }
  145.  
  146. /*--------------------------------------------------------------------*/
  147.  
  148. char *cmdlst[] = {
  149.     "",
  150.     "Command Summary -- Type only the first letter of a command",
  151.     "",
  152.     "MESSAGE HANDLING:                NAVIGATION:",
  153.     "Answer [message #(s)]                Backup to prev msg & type it",
  154.     "Forward [message #(s)]                Next message & type it",
  155.     "Send (compose) a new message            Headers of [message #(s)]",
  156.     "Type [message #(s)] onto terminal        Go to message #",
  157.     "Delete [message #(s)]                Current message # is typed",
  158.     "Undelete [message #(s)]",        
  159.     "Keep [message #(s)]                        /-same as dcn",
  160.     "Y-Resend [message #(s)]",
  161.     "Z-Two window answer",
  162.     "",
  163.     "FILE HANDLING:                    MISCELLANEOUS:",
  164.     "Exit and update -- normal exit            Jump into sub-Shell",
  165.     "List [message #(s)] into text file        Xtra user options",
  166.     "Overwrite old file                : current date and time",
  167.     "Put [message #(s)] into msg file        ; ignore rest of line",
  168.     "Quit -- fast exit                @ Undigestify",
  169.     "Read another msg file                ! sub-Shell",
  170.     "Move [message #(s)] into msg file & mark as deleted",
  171.     "",
  172.     "Examples of message #(s) are:  42  1-4  2,5,7-.  1-5,7-@  c  32-$",
  173.     0
  174. };
  175.  
  176. char *xtcmdlst[] = {
  177.     "",
  178.     "xtra options command summary -- Type only the first letter of a command",
  179.     "",
  180.     "Binary file write",
  181.     "Control char filter (on/off)",
  182.     "Exit without saves",
  183.     "List message body",
  184.     "Mark message",
  185.     "Numbered message lists (on/off)",
  186.     "Output mbox file",
  187.     "Paging (on/off)",
  188.     "Reorder (sort) msg file",
  189.     "Strip keywords (on/off)",
  190.     "Verbose (on/off)",
  191.     "Xtra options status",
  192.     0
  193. };
  194.  
  195. /*
  196.  *            H E L P
  197.  */
  198. help(helplist)
  199. char *helplist[];
  200. {
  201.     register unsigned int i;
  202.  
  203.     tt_norm();
  204.     for( i = 0; helplist[i] != 0; i++)
  205.         printf( "%s\r\n", helplist[i]);
  206.     tt_raw();
  207. }
  208.  
  209. /*--------------------------------------------------------------------*/
  210.  
  211. /*
  212.  *            G I T R
  213.  *
  214.  *  Get message range.
  215.  */
  216. gitr()
  217. {
  218.     if( status.ms_nmsgs == 0)  {
  219.         printf( "'%s' is empty\r\n", filename);
  220.         error( "" );
  221.     }
  222.  
  223.     unset();
  224.  
  225.     if( !gitrtype())
  226.         gitrnum();
  227.  
  228.     if( cntproc() == 0)
  229.         error( " no such messages\r\n");
  230. }
  231.  
  232. /*
  233.  *            G I T R T Y P E
  234.  *
  235.  * Get range type.  Alphabetic answers are processed here,
  236.  * numerics are left alone (FALSE return).
  237.  */
  238. gitrtype()
  239. {
  240.     char cmd;
  241.  
  242.     cmd = nxtchar;
  243.     nxtchar = rdnxtfld();
  244.     nxtchar = uptolow(nxtchar);
  245.  
  246.     if( cmd == 'g' )  {
  247.         /* Only numerics valid for GOTO command */
  248.         if( isalpha( nxtchar) && nxtchar != 'c' && nxtchar != 'm')
  249.             error( "...not legal for this command\r\n");
  250.     }
  251.  
  252.     switch( nxtchar)  {
  253.     case 'a': 
  254.         if( verbose)
  255.             printf( "all");
  256.         if( cmd != 'h' ) {
  257.             if( !confirm((char *)0,DOLF) )
  258.                 error("");
  259.         }
  260.         else if (verbose)
  261.             printf("\r\n");
  262.         setrange( 1, status.ms_nmsgs);
  263.         break;
  264.  
  265.     case 'c': 
  266.         if( verbose)
  267.             printf( "current\r\n");
  268.         if( status.ms_curmsg == 0)  {
  269.             if( status.ms_nmsgs != 0)
  270.                 status.ms_curmsg = 1;
  271.             else
  272.                 if( status.ms_curmsg > status.ms_nmsgs)
  273.                     error( "no current message\r\n");
  274.         }
  275.         setrange( status.ms_curmsg, status.ms_curmsg);
  276.         break;
  277.  
  278.     case 'd': 
  279.         if( verbose)
  280.             printf( "deleted messages\r\n");
  281.         settype( 'd');
  282.         if( cntproc() == 0)
  283.             error( "no deleted messages\r\n");
  284.         break;
  285.  
  286.     case 'e': 
  287.         if( verbose)
  288.             printf( "expression: ");
  289.         key[0] = rdnxtfld();
  290.         gather( key, 79);
  291.         if (key[0])
  292.             settype( 'e');
  293.         break;
  294.  
  295.     case 'f': 
  296.         if( verbose)
  297.             printf( "from: ");
  298.         key[0] = rdnxtfld();
  299.         gather( key, 79);
  300.         if (key[0])
  301.             settype( 'f');
  302.         break;
  303.  
  304.     case 'i': 
  305.         if( verbose)
  306.             printf( "inverse ");
  307.         ascending = FALSE;    /* flag for doiter() */
  308.  
  309.         if( !gitrtype() )    /* RECURSE */
  310.             gitrnum();
  311.         return( TRUE );
  312.  
  313.     case 'k':
  314.         if( verbose )
  315.             printf( "kept messages" );
  316.  
  317.         if( cmd == 'd' ) {
  318.             if( !confirm((char *)0,DOLF) )
  319.                 error("");
  320.         }
  321.         else if (verbose)
  322.             printf("\r\n");
  323.  
  324.         settype( 'k' );
  325.         break;
  326.  
  327.     case 'l':
  328.         if( verbose)
  329.             printf( "leaving" );
  330.  
  331.         if( !ismainbox )
  332.             error( "\r\nNot main mailbox - no messages will leave\r\n");
  333.  
  334.         if( cmd == 'd' ) {
  335.             if( !confirm((char *)0,DOLF) )
  336.                 error("");
  337.         }
  338.         else if (verbose)
  339.             printf("\r\n");
  340.  
  341.         settype( 'l' );
  342.         break;
  343.  
  344.     case 'm':
  345.         if(verbose)
  346.             printf( "mark\r\n");
  347.         if( status.ms_markno > 0 && status.ms_markno <= status.ms_nmsgs )
  348.             setrange(status.ms_markno, status.ms_markno);
  349.         else
  350.             error("no mark set\r\n");
  351.         break;
  352.  
  353.     case 'n':
  354.         if( verbose)
  355.             printf( "new");
  356.  
  357.         if( cmd == 'd' ) {
  358.             if( !confirm((char *)0,DOLF) )
  359.                 error("");
  360.         }
  361.         else if (verbose)
  362.             printf("\r\n");
  363.  
  364.         settype( 'n' );
  365.         break;
  366.  
  367.     case 's': 
  368.         if( verbose)
  369.             printf( "subject: ");
  370.         key[0] = rdnxtfld();
  371.         gather( key, 79);
  372.         if (key[0])
  373.             settype( 's');
  374.         break;
  375.  
  376.     case 't': 
  377.         if( verbose)
  378.             printf( "to: ");
  379.         key[0] = rdnxtfld();
  380.         gather( key, 79);
  381.         if (key[0])
  382.             settype( 't');
  383.         break;
  384.  
  385.     case 'u': 
  386.         if( verbose)
  387.             printf( "undeleted messages");
  388.  
  389.         if( cmd == 'd' ) {
  390.             if( !confirm((char *)0,DOLF) )
  391.                 error("");
  392.         }
  393.         else if (verbose)
  394.             printf("\r\n");
  395.  
  396.         settype( 'u');
  397.         if( cntproc() == 0)
  398.             error( "no undeleted messages\r\n");
  399.         break;
  400.  
  401.     case '?':
  402.         printf( "\r\na message sequence:\r\n");
  403.         printf( " a(ll), c(urrent), d(eleted), e(xpression), f(rom), l(eaving),\r\n");
  404.         printf( " k(ept), m(ark), n(new), i(inverse), s(ubject), t(o), u(ndeleted)\r\n");
  405.         printf( " or a number or list of numbers of the form\r\n");
  406.         printf( " (#  #-#  #,#,#,#  $ .-$)  .=current @=mark $=last\r\n" );
  407.         error( "" );
  408.  
  409.     case '\003':
  410.         error(" ^C\r\n");
  411.         
  412.     case '\004':
  413.         error(" ^D\r\n");
  414.  
  415.     case '\n': 
  416.         if( status.ms_curmsg == 0)  {
  417.             if( status.ms_nmsgs != 0)
  418.                 status.ms_curmsg = 1;
  419.             else
  420.                 if( status.ms_curmsg > status.ms_nmsgs)
  421.                     error( "no current message\r\n");
  422.         }
  423.         if( cmd == 'g' && status.ms_markno > 0 && status.ms_markno <= status.ms_nmsgs )
  424.             status.ms_curmsg = status.ms_markno;
  425.         setrange( status.ms_curmsg, status.ms_curmsg);
  426.         switch( cmd)  {
  427.  
  428.         case 'a': 
  429.         case 'f': 
  430.         case 'h': 
  431.         case 't': 
  432.         case 'y':
  433.         case 'z':
  434.             if (verbose) printf("\r\n");
  435.             break;      /* message number is printed in header */
  436.  
  437.         default: 
  438.             /* Print brief header */
  439.             printf( "\r\n # %d  %s\r\n", status.ms_curmsg,
  440.                 msgp[status.ms_curmsg-1]->from);
  441.         }              /* DROP ON THROUGH */
  442.         break;
  443.  
  444.     default: 
  445.         return( FALSE);
  446.     }
  447.     if (!verbose) suckup();
  448.     return( TRUE);
  449. }
  450.  
  451. /*
  452.  *            G I T R N U M
  453.  *
  454.  * Get range -- numeric case
  455.  */
  456. gitrnum()
  457. {
  458.     unsigned int getn;
  459.     unsigned int mbegin, mend;
  460.  
  461.     key[0] = nxtchar;
  462.     gather( key, 78 );
  463.     gc = key;
  464.  
  465.     while( *gc != '\000' )  {
  466.         switch( *gc )  {
  467.  
  468.         case ' ':
  469.         case ',':
  470.             gc++;
  471.         }
  472.  
  473.         if( *gc == '\000')
  474.             break;
  475.  
  476.         getn = getnum( &mbegin);
  477.         mend = mbegin;
  478.  
  479.         switch( *gc )  {
  480.  
  481.         case '\000': 
  482.         case ' ': 
  483.         case ',': 
  484.             if( mbegin == 0 || mbegin > status.ms_nmsgs)
  485.                 error( "bad number (type ? for help)\r\n");
  486.             break;
  487.  
  488.         case '>': 
  489.         case '-':           /* ;2 Replace range delimiters */
  490.         case ':':           /* ;2 Replace range delimiters */
  491.             if( getn == 0)
  492.                 mbegin = 1;
  493.             if( mbegin == 0 || mbegin > status.ms_nmsgs)
  494.                 error( " bad first number (type ? for help)\r\n");
  495.  
  496.             gc++;
  497.             getn = getnum( &mend);
  498.  
  499.             if( getn == 0)
  500.                 mend = status.ms_nmsgs;
  501.             else
  502.                 if( mend > status.ms_nmsgs)  {
  503.                     printf( "... %d is last message\r\n", status.ms_nmsgs);
  504.                     mend = status.ms_nmsgs;
  505.                 }
  506.             if( mend == 0)
  507.                 error( "bad last number (type ? for help)\r\n");
  508.             break;
  509.  
  510.         default: 
  511.             error( " bad message number (type ? for help)\r\n");
  512.         }
  513.         setrange( mbegin, mend);
  514.     }
  515. }
  516.  
  517. /*--------------------------------------------------------------------*/
  518.  
  519. /*
  520.  *            U N S E T
  521.  *
  522.  * Clear all the M_PROCESS_IT flags.  Used prior to setting ranges, etc.
  523.  */
  524. unset()
  525. {
  526.     register struct message **mp;
  527.  
  528.     /* set all the flags to zero */
  529.     for( mp = &msgp[status.ms_nmsgs]; mp-- != &msgp[0]; )
  530.         (*mp)->flags &= ~M_PROCESS_IT;
  531. }
  532.  
  533. /*
  534.  *            C N T P R O C
  535.  *
  536.  * Count how many messages to process.
  537.  */
  538. cntproc()
  539. {
  540.     register unsigned int nproc;
  541.     register struct message **mp;
  542.  
  543.     nproc = 0;
  544.     for( mp = &msgp[status.ms_nmsgs]; mp-- != &msgp[0]; )
  545.         if( (*mp)->flags & M_PROCESS_IT)
  546.             nproc++;
  547.     return( nproc);
  548. }
  549.  
  550. /*
  551.  *            S E T R A N G E 
  552.  *
  553.  * set group of messages to process
  554.  */
  555. setrange( mbegin, mend )
  556. register unsigned int mbegin;
  557. register unsigned int mend;
  558. {
  559.     if( mbegin == 0 )
  560.         mbegin = 1;
  561.     if( mend > Nmsgs )
  562.         mend = Nmsgs;
  563.  
  564.     while( mend-- >= mbegin)
  565.         msgp[mend]->flags |= M_PROCESS_IT;
  566. }
  567.  
  568. /*
  569.  *            S E T T Y P E
  570.  */
  571. settype( type )
  572. char type;
  573. {
  574.     register struct message **mp;
  575.     register unsigned int i;
  576.  
  577.     switch( type )  {
  578.  
  579.     case 'd':
  580.         for( mp = &msgp[status.ms_nmsgs]; mp-- != &msgp[0]; )
  581.             if( (*mp)->flags & M_DELETED)
  582.                 (*mp)->flags |= M_PROCESS_IT;
  583.         break;
  584.  
  585.     case 'n':
  586.         for( mp = &msgp[status.ms_nmsgs]; mp-- != &msgp[0]; )
  587.             if( (*mp)->flags & M_NEW)
  588.                 (*mp)->flags |= M_PROCESS_IT;
  589.         break;
  590.  
  591.     case 'k':
  592.         for( mp = &msgp[status.ms_nmsgs]; mp-- != &msgp[0]; )
  593.             if( (*mp)->flags & M_KEEP)
  594.                 (*mp)->flags |= M_PROCESS_IT;
  595.         break;
  596.  
  597.     case 'u':
  598.         for( i = status.ms_nmsgs; i-- != 0;)
  599.             if( !(msgp[i]->flags & M_DELETED))
  600.                 msgp[i]->flags |= M_PROCESS_IT;
  601.         break;
  602.  
  603.     case 's':
  604.         for( i = status.ms_nmsgs; i-- != 0; )
  605.             if( strindex( key, msgp[i]->subject) >= 0)
  606.                 msgp[i]->flags |= M_PROCESS_IT;
  607.         break;
  608.  
  609.     case 'f':
  610.         for( i = status.ms_nmsgs; i-- != 0; )
  611.             if( prefix( msgp[i]->from, "To:"))  {
  612.                 if( prefix( key, username))
  613.                     msgp[i]->flags |= M_PROCESS_IT;
  614.             }  else  {
  615.                 if( strindex( key, msgp[i]->from) >= 0)
  616.                     msgp[i]->flags |= M_PROCESS_IT;
  617.             }
  618.         break;
  619.  
  620.     case 't':
  621.         for( i = status.ms_nmsgs; i-- != 0; )
  622.             if( strindex( key, msgp[i]->to ) >= 0 )
  623.                 msgp[i]->flags |= M_PROCESS_IT;
  624.         break;
  625.  
  626.     case 'e':
  627.         tt_norm();
  628.         for( msgno = 0; msgno < status.ms_nmsgs; msgno++)
  629.             if(txtmtch())
  630.                 msgp[msgno]->flags |= M_PROCESS_IT;
  631.         tt_raw();
  632.         break;
  633.  
  634.     case 'l':
  635.         tt_norm();
  636.         for( mp = &msgp[status.ms_nmsgs]; mp-- != &msgp[0]; )
  637.             if(    !((*mp)->flags & M_KEEP)
  638.                 && !((*mp)->flags & M_DELETED)
  639.                 && !((*mp)->flags & M_NEW))
  640.                 (*mp)->flags |= M_PROCESS_IT;
  641.         tt_raw();
  642.         break;
  643.  
  644.     default:
  645.         error("bad settype() call");
  646.     }
  647. }
  648.  
  649. /*
  650.  *            G E T N U M
  651.  */
  652. getnum( result)
  653. unsigned int *result;
  654. {
  655.     register unsigned int i;
  656.     register unsigned int n;
  657.  
  658.     i = n = 0;
  659.     while( *gc == ',' || *gc == '-' || *gc == '>' || *gc == ':' )
  660.         gc++;
  661.     if( *gc == '$')  {
  662.         *result = status.ms_nmsgs;
  663.         gc++;
  664.         return( TRUE);
  665.     } else if ( *gc == '.') {
  666.         *result = status.ms_curmsg;
  667.         gc++;
  668.         return( TRUE );
  669.     } else if ( *gc == '@' ) {
  670.         if( status.ms_markno > 0 && status.ms_markno <= status.ms_nmsgs )
  671.             *result = status.ms_markno;
  672.         else
  673.             error("no mark set\r\n");
  674.         gc++;
  675.         return( TRUE );
  676.     }
  677.     while( isdigit( *gc ) )  {
  678.         n = n * 10 + *gc - '0';
  679.         i++;
  680.         gc++;
  681.     }
  682.  
  683.     *result = n;
  684.     return( i);
  685. }
  686.  
  687. /*--------------------------------------------------------------------*/
  688.  
  689. /*
  690.  *            D O I T E R
  691.  *
  692.  * do iteration on message numbers
  693.  */
  694. doiter( fn)
  695. int ( *fn)();
  696. {
  697.     unsigned int lastdone;
  698.  
  699.     if( status.ms_nmsgs == 0)
  700.         return;
  701.     tt_norm();
  702.     lastdone = msgno;
  703.     if( ascending == TRUE )  {
  704.         /* process in ascending order */
  705.         for( msgno = 1; msgno <= status.ms_nmsgs; msgno++)
  706.             if( (mptr = msgp[msgno-1])->flags & M_PROCESS_IT)  {
  707.                 (*fn)();
  708.                 lastdone = msgno;
  709.             }
  710.     }  else  {
  711.         /* Process in inverse (descending) order */
  712.         for( msgno = status.ms_nmsgs; msgno > 0; msgno-- )
  713.             if( (mptr = msgp[msgno-1])->flags & M_PROCESS_IT)  {
  714.                 (*fn)();
  715.                 lastdone = msgno;
  716.             }
  717.     }
  718.     tt_raw();
  719.     msgno = lastdone;
  720. }
  721.  
  722. /*-----------------------------------------------------------------------
  723.  *              R E S E N D M S G
  724.  *  
  725.  *  Resend message to addressees
  726.  */
  727. resendmsg() {
  728.  
  729.     register int savepretty;
  730.  
  731.     if( verbose )
  732.         putchar('.');
  733.     lstsep = FALSE;
  734.     lstmore = FALSE;
  735.     savepretty = prettylist;
  736.     prettylist = OFF;
  737.     cpyiter( lstmsg, NOIT,( int( *)()) 0);
  738.     prettylist = savepretty;
  739.     mptr->flags |= M_FORWARDED;
  740. }
  741. /*            S O R T B O X
  742.  *  
  743.  */
  744. sortbox() {
  745.  
  746.     register int i,j,k;
  747.     struct message *mpt;
  748.     char *pi, *pj;
  749.  
  750.     if( status.ms_nmsgs == 0)  {
  751.         printf( "'%s' is empty\r\n", filename);
  752.         error( "" );
  753.     }
  754.  
  755.     nxtchar = rdnxtfld();
  756.     nxtchar = uptolow(nxtchar);
  757.     switch( nxtchar)  {
  758.  
  759.     case 'd':
  760.         if( verbose )
  761.             printf("Date\r\n");
  762.         break;
  763.  
  764.     case 'f': 
  765.         if( verbose)
  766.             printf("From\r\n");
  767.         break;
  768.  
  769.     case 'r':
  770.         if( verbose )
  771.             printf("date and subject\r\n");
  772.         fflush(stdout);
  773.         /* sort by date first */
  774.         nxtchar = 'd';
  775.         qsort( &msgp[0], status.ms_nmsgs, sizeof(msgp[0]), qcomp );
  776.  
  777.         /* Match subjects */
  778.         for( i = 0; i < status.ms_nmsgs-1; i++ ) {
  779.             if( msgp[i]->subject[0] == '\0' )
  780.                 continue;
  781.             for( pi = msgp[i]->subject; prefix( pi, "Re:" ) == TRUE; )
  782.                 pi = strend("Re:",pi);
  783.  
  784.             for( j = i+1; j < status.ms_nmsgs; j++ ) {
  785.                 if( msgp[j]->subject[0] == '\0' )
  786.                     continue;
  787.                 for( pj = msgp[j]->subject; prefix( pj, "Re:" ) == TRUE; )
  788.                     pj = strend("Re:",pj);
  789.  
  790.                 if( lexnequ( pi, pj, SIZESUBJ ) != TRUE )
  791.                     continue;
  792.  
  793.                 /* Match - move rest down a slot */
  794.                 if( j == i+1 ) {    /* No need to move */
  795.                     i++;
  796.                     continue;
  797.                 }
  798.                 mpt = msgp[j];
  799.                 for( k = j-1; k > i; k-- )
  800.                     msgp[k+1] = msgp[k];
  801.                 msgp[i+1] = mpt;
  802.                 i++;
  803.             }
  804.         }
  805.         return;
  806.  
  807.     case 's': 
  808.         if( verbose)
  809.             printf( "Subject\r\n");
  810.         break;
  811.  
  812.     case 't':
  813.         if( verbose )
  814.             printf("To\r\n");
  815.         break;
  816.  
  817.     case '?':
  818.         printf( "\r\nd(ate), f(rom), r( date & subject), s(ubject), t(o)\r\n");
  819.         error( "" );
  820.  
  821.     case '\004':
  822.         error( " ^D\r\n" );
  823.  
  824.     default:
  825.         error( "" );
  826.     }
  827.  
  828.     fflush(stdout);
  829.     qsort( &msgp[0], status.ms_nmsgs, sizeof(msgp[0]), qcomp);
  830. }
  831.  
  832. /*            Q C O M P
  833.  *  
  834.  *  Comparison routine called by qsort
  835.  */
  836. qcomp(pa,pb)
  837. struct message **pa, **pb;
  838. {
  839.     int sval;
  840.     char *cpa, *cpb;
  841.     
  842.     switch( nxtchar ) {
  843.  
  844.     case 'd':
  845.         return(datecmp((*pa)->date, (*pb)->date));
  846.  
  847.     case 'f': 
  848.         return(lexrel( (*pa)->from, (*pb)->from ));
  849.  
  850.     case 's': 
  851.         /* Remove all Re: */
  852.         for( cpa = (*pa)->subject; prefix( cpa, "Re:" ) == TRUE; )
  853.             cpa = strend("Re:",cpa);
  854.         for( cpb = (*pb)->subject; prefix( cpb, "Re:" ) == TRUE; )
  855.             cpb = strend("Re:",cpb);
  856.         if( (sval = lexrel( cpa, cpb )) == 0 )
  857.             return(datecmp((*pa)->date, (*pb)->date));
  858.         else
  859.             return(sval);
  860.  
  861.     case 't':
  862.         return( lexrel( (*pa)->to, (*pb)->to ) );
  863.  
  864.     default:
  865.         error( "Bad type in qcomp" );
  866.     }
  867.     /*NOTREACHED*/
  868. }
  869.  
  870. datecmp(a, b)
  871. long a, b;
  872. {
  873.     if ((a - b) < 0)
  874.         return (-1);
  875.     if ((a - b) > 0)
  876.         return (1);
  877.     return(0);
  878. }
  879.